#include <linux/fs.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>

MODULE_LICENSE("GPL");

//MODUlE_AUTHOR("liusanjie");
struct mouse_key_value  //structure to recive  mouse input
{
	int lpress;   //left key value
	int rpress;   //right key value 
	int x;        //relative x value
	int y;		//relative y value
};
static struct input_dev *vms_input_dev;  
static struct kobject mouse_kobj;
static struct timer_list   rkey_timer;
static struct mouse_key_value  *mkv;

void rkey_fun(unsigned long a)       //funtion  conected to timer
{
	
	input_report_key(vms_input_dev,BTN_RIGHT,1);   //beat the right key button
	input_report_rel(vms_input_dev, REL_X, mkv->x); 
	input_report_rel(vms_input_dev, REL_Y, mkv->y);
	input_sync(vms_input_dev);
//	input_report_key(vms_input_dev,BTN_RIGHT,0);   //fold the right key button
//	input_sync(vms_input_dev);

}
//fuction to handle key beat and input envent                                   
static ssize_t  mouse_store(struct kobject *kobj, struct device_attribute *attr, const char *buffer, size_t count)  
{
	mkv = (struct mouse_keyvalue *) buffer;
	printk("%d %d %d %d\n",mkv->lpress,mkv->rpress,mkv->x,mkv->y);
	if(mkv->lpress == 1 && mkv->rpress!=1)                  
	{
		input_report_key(vms_input_dev, BTN_LEFT, 1);
                input_report_rel(vms_input_dev,REL_X,mkv->x);
                input_report_rel(vms_input_dev,REL_Y,mkv->y);
//		input_sync(vms_input_dev);
  //              input_report_key(vms_input_dev,BTN_LEFT,0);
                input_sync(vms_input_dev);

	}
	else if(mkv->rpress == 1 && mkv->lpress != 1)
	{
		if(!timer_pending(&rkey_timer)) //   timer  on a list or not 
		{
			mod_timer(&rkey_timer,jiffies+2*HZ);  //update the expire time
		}
		else
		{
		}
	}
	else 
	{
		input_report_rel(vms_input_dev,REL_X,mkv->x);
		input_report_rel(vms_input_dev,REL_Y,mkv->y);
		input_sync(vms_input_dev);
	}
	
	return count;
}


void kobj_release(struct kobject *kobj)
{
	printk(KERN_INFO"kobject release\n");
}

struct attribute  mouse_attr=
{
	.name="mouseattr",
	.mode=S_IRWXUGO,
};

struct attribute  kobj_attr[]=
{
	&mouse_attr,
	NULL
};

struct sysfs_ops mouse_ops=
{
	.store=mouse_store,
};



struct kobj_type ktype=
{
	.release=kobj_release,
	.sysfs_ops=&mouse_ops,
	.default_attrs=kobj_attr,
};

void input_dev_setup()     //setup key  code that can be handled
{
	vms_input_dev->name="mouse_input";
	
	set_bit(EV_REL, vms_input_dev->evbit); 
	set_bit(REL_X, vms_input_dev->relbit); 
	set_bit(REL_Y, vms_input_dev->relbit);
	
	set_bit(EV_KEY, vms_input_dev->evbit); 
	set_bit(BTN_LEFT, vms_input_dev->keybit); 
	set_bit(BTN_RIGHT, vms_input_dev->keybit); 
}



int __init vms_init(void)
{
	int result=0;
	result=kobject_init_and_add(&mouse_kobj,&ktype,NULL,"kobj_mouse");  // init and add  the kobject to the kernel
	if(result)
	{
		printk(KERN_INFO"Failed to add kobj\n");
		return result;
	}

	vms_input_dev = input_allocate_device();
	if(!vms_input_dev) 
	{
		printk(KERN_INFO"Bad input_alloc_device()\n");
	}
	input_dev_setup();	
	input_register_device(vms_input_dev);
	init_timer(&rkey_timer);
	rkey_timer.expires=jiffies+HZ;
	rkey_timer.function=rkey_fun;
	
	return 0;
}
.tmp_versions

void __exit vms_exit(void)
{
	
	kobject_del(&mouse_kobj);
	input_unregister_device(vms_input_dev);
	del_timer(&rkey_timer);
	
}
module_init(vms_init);
module_exit(vms_exit);
